package cn.ante.ymcc.service.impl;

import cn.ante.ymcc.constance.RedisConstant;
import cn.ante.ymcc.domain.MessageSmsPullblack;
import cn.ante.ymcc.dto.RedisSMSCodeValueDto;
import cn.ante.ymcc.dto.RegisterDto;
import cn.ante.ymcc.exception.GlobalException;
import cn.ante.ymcc.result.JSONResult;
import cn.ante.ymcc.service.IMessageSmsPullblackService;
import cn.ante.ymcc.service.IMessageSmsService;
import cn.ante.ymcc.util.AssertUtil;
import cn.ante.ymcc.util.StrUtils;
import cn.ante.ymcc.util.VerifyCodeUtils;
import cn.ante.ymcc.config.VerifyCodeProperties;
import cn.ante.ymcc.constance.CommonExceptionEnum;
import cn.ante.ymcc.service.IVerifyCodeService;
import cn.ante.ymcc.domain.MessageSms;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private IMessageSmsService messageSmsService;

    @Autowired
    private VerifyCodeProperties verifyCodeProperties;

    @Autowired
    private IMessageSmsPullblackService messageSmsPullblackService;

    /*
     * @Description: 图形验证码生成
     * @Author: Nai
     * @Version: 1.0
     * @Date:  2022/8/6 23:49
     */
    @Override
    public String graph(String imageCodeKey) {
        // 判断参数是否为空
        AssertUtil.isNotEmpty(imageCodeKey, CommonExceptionEnum.IMG_CODE_KEY.getMessage(),CommonExceptionEnum.IMG_CODE_KEY.getCode());
        // 随机获得验证码
        String code = StrUtils.getComplexRandomString(verifyCodeProperties.getImgCodeLength());
        // 将验证码存入redis中
        redisTemplate.opsForValue().set(imageCodeKey,code,verifyCodeProperties.getImgCodeExpire(), TimeUnit.MINUTES);

        // 将code进行编码传递
        String base64Str = VerifyCodeUtils.verifyCode(100, 35, code);

        return base64Str;
    }


    /*
    * @Description: 手机验证码生成
    * @Author: Nai
    * @Version: 1.0
    * @Date:  2022/8/6 23:49
    */
    @Override
    public JSONResult sendSmsCode(RegisterDto dto) {
        // 判断图像验证码是否正确
        Boolean aBoolean = checkImgCode(dto.getImageCodeKey(),dto.getImageCode());
        AssertUtil.isTrue(aBoolean,CommonExceptionEnum.IMG_CODE_ERROR.getMessage(),CommonExceptionEnum.IMG_CODE_ERROR.getCode());

        // 判断手机号是否存在与黑名单中，如果存在就不再发送消息
        List<MessageSmsPullblack> messageSmsPullBlacks = messageSmsPullblackService.selectList(null);
        HashMap<String, MessageSmsPullblack> map = new HashMap<>();
        for (MessageSmsPullblack mb: messageSmsPullBlacks) {
            map.put(mb.getPhone(),mb);
        }
        AssertUtil.isNull(map.get(dto.getMobile()), CommonExceptionEnum.MESSAGE_PULL_BLACK.getCode(),
                CommonExceptionEnum.MESSAGE_PULL_BLACK.getMessage());

        // 判断手机验证码是否存在
        RedisSMSCodeValueDto redisSMSCodeValueDto = creatSmsCodeValue(dto);
        String redisKey = RedisConstant.REDIS_SMS_CODE_PREFIX + dto.getMobile();
        redisTemplate.opsForValue().set(redisKey, redisSMSCodeValueDto, verifyCodeProperties.getExpire(), TimeUnit.MINUTES);


        // 使用短信将code发送给用户
        String message = sendSMSCode(dto.getMobile(),redisSMSCodeValueDto.getCode());

        // 将发送的短信存入数据库中
        insertSMSSendLog(dto,message);
        return JSONResult.success();
    }
    /*
    * @Description: 使用短信将code发送给用户,此处先省略
    * @Author: Nai
    * @Version: 1.0
    * @Date:  2022/8/6 23:58
    */
    private String sendSMSCode(String code,String mobie){
        log.info("你的手机号是("+mobie+")拿去你的验证码" + code);
        return "你的手机号是("+mobie+")拿去你的验证码" + code;
    }

    /**
     * ,将消息存入数据库中
     *
     */
    private void insertSMSSendLog(RegisterDto dto,String message){
        //创建消息实体类
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle("用户注册短信验证码");
        messageSms.setContent(message);

        //获取ip地址 start
        ServletRequestAttributes servletRequestAttributes =  (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
        messageSms.setIp( httpServletRequest.getRemoteAddr());
        //获取ip地址 end
//        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        messageSms.setSendTime(new Date());
        messageSms.setPhone(dto.getMobile());
        messageSmsService.insert(messageSms);
        log.info("=======================================");
        log.info(messageSms.getId().toString());
    }


    /*
    * @Description: 检验图像验证码
    * @Author: Nai
    * @Version: 1.0
    * @Date:  2022/8/6 23:46
    */
    private Boolean checkImgCode(String imageCodeKey,String imageCode){
        Object redisImgCode = redisTemplate.opsForValue().get(imageCodeKey);
        if (!redisImgCode.toString().equalsIgnoreCase(imageCode)){
            return false;
        }
        return true;
    }

    /*
     * @Description: 将redis中的手机验证码的值code+时间戳作为对象存储；
     * @Author: Nai
     * @Version: 1.0
     * @Date:  2022/8/6 23:46
     */
    private RedisSMSCodeValueDto creatSmsCodeValue(RegisterDto dto){
        // 都为真之后，开始发送手机验证码
        String smsCodeKey = RedisConstant.REDIS_SMS_CODE_PREFIX + dto.getMobile();
        // 再redis中查找是否有该验证码
        RedisSMSCodeValueDto redisSmsCodeDto = (RedisSMSCodeValueDto)redisTemplate.opsForValue().get(smsCodeKey);
        if (redisSmsCodeDto == null) {
            redisSmsCodeDto = new RedisSMSCodeValueDto(StrUtils.getComplexRandomString(verifyCodeProperties.getLength()),new Date());
            return redisSmsCodeDto;
        }
        Date creatTime = redisSmsCodeDto.getCreatTime();
        if ((System.currentTimeMillis() - creatTime.getTime())/1000 < verifyCodeProperties.getInterval()) {
            throw new GlobalException(CommonExceptionEnum.SEND_SMS_TIME.getMessage(), CommonExceptionEnum.SEND_SMS_TIME.getCode());
        }
        return redisSmsCodeDto;
    }



}
